package com.shop.admin.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shop.admin.dao.*;
import com.shop.admin.dto.CouponRuleDTO;
import com.shop.admin.dto.PageCouponBatchDTO;
import com.shop.admin.entity.*;
import com.shop.admin.service.*;
import com.shop.admin.utils.PageUtils;
import com.shop.admin.vo.CategoryUnderProductsVo;
import com.shop.admin.vo.CouponRuleVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

@Service
public class CouponRuleServiceImpl extends ServiceImpl<CouponRuleDao, CouponRule> implements CouponRuleService {

    private static final Logger couponRuleLog = LoggerFactory.getLogger(CouponRuleServiceImpl.class);

    @Resource
    private CouponRuleDao couponRuleDao;

    @Resource
    private RuleNeedDao ruleNeedDao;

    @Resource
    private CouponBatchDao couponBatchDao;

    @Resource
    private RuleNeedService ruleNeedService;

    @Resource
    private ShopOrderDao orderDao;

    @Resource
    private ShopCategoryDao categoryDao;

    @Resource
    private ThreadPoolExecutor threadPoolExecutor;

//    @FunctionalInterface
//    public interface couponBatchDTOConvert<S,T> {
//        T convertForBatch(S s);
//    }

    @Override
    public PageUtils queryPageCouponRule(PageCouponBatchDTO pageCouponBatchDTO) {
        Page<CouponRuleVo> resPage = getCouponRuleResPage(pageCouponBatchDTO);
        if (CollectionUtils.isEmpty(resPage.getRecords())) {
            return new PageUtils(null);
        }
        List<CouponRuleVo> couponCollect = couponRuleVoSetNeed(resPage.getRecords());
        resPage.setRecords(couponCollect);
        PageUtils pageUtils = new PageUtils(resPage);
        return pageUtils;
    }

    @Override
    @Transactional
    public boolean saveCoupon(CouponRuleDTO couponRuleDTO) {
        if (getCouponNameJudgment(couponRuleDTO.getCouponName())){
            CouponRule couponRule = couponRuleDTO.convertToRule();
            CompletableFuture<Integer> couponRuleCompletableFuture = CompletableFuture.
                    supplyAsync(() -> this.baseMapper.insert(couponRule), threadPoolExecutor);

            Integer ruleId = couponRule.getRuleId();
            CouponBatch couponBatch =couponRuleDTO.convertToBatch();
            couponBatch.setRuleId(ruleId);
            CompletableFuture<Integer> couponBatchCompletableFuture = couponRuleCompletableFuture.
                    thenApplyAsync((res) -> couponBatchDao.insert(couponBatch), threadPoolExecutor);

            CompletableFuture<Boolean> ruleNeedCompletableFuture = couponRuleCompletableFuture.thenApplyAsync((res) -> {
                ruleNeedService.saveRule(couponRuleDTO, ruleId);
                return true;
            }, threadPoolExecutor);
            CompletableFuture.allOf(couponBatchCompletableFuture,ruleNeedCompletableFuture);
            return true;
        }
        return false;
    }


    @Override
    @Transactional
    public boolean updateCoupon(CouponRuleDTO couponRuleDTO) {
        if (getCouponNameJudgment(couponRuleDTO.getCouponName())){
            CouponRule couponRule = couponRuleDTO.convertToRule();
            this.baseMapper.updateById(couponRule);
            Integer ruleId = couponRuleDTO.getRuleId();
            CouponBatch couponBatch = couponRuleDTO.convertToBatch();
            couponBatch.setRuleId(ruleId);
            couponBatchDao.update(couponBatch,new QueryWrapper<CouponBatch>().lambda().eq(CouponBatch::getRuleId,ruleId));
            ruleNeedService.updateRule(couponRuleDTO,ruleId);
            return true;
        }
        return false;
    }

    @Override
    public List<CategoryUnderProductsVo> categoryUnderProducts() {
        List<ShopCategory> shopCategories = categoryDao.selectList(null);

        List<CategoryUnderProductsVo> categoryUnderProductsVoCollect = shopCategories.stream().map(category -> {
            CategoryUnderProductsVo categoryUnderProductsVo = new CategoryUnderProductsVo();
            categoryUnderProductsVo.setCategoryId(category.getCateId()).setCategoryName(category.getCateName());
            return categoryUnderProductsVo;
        }).collect(Collectors.toList());

        List<CategoryUnderProductsVo> CategoryUnderProductsVos = categoryUnderProductsVoCollect.stream().map(menu -> {
            menu.setProductsVos(getProductsVos(menu));
            return menu;
        }).collect(Collectors.toList());
        return CategoryUnderProductsVos;
    }

    private List<CategoryUnderProductsVo.ProductsVo> getProductsVos(CategoryUnderProductsVo menu) {
        List<ShopOrder> shopOrderList = orderDao.selectList(new QueryWrapper<ShopOrder>().lambda().select(ShopOrder::getOrderId, ShopOrder::getOrderName).eq(ShopOrder::getCatelogId, menu.getCategoryId()));
        List<CategoryUnderProductsVo.ProductsVo> productsVos = shopOrderList.stream().map(order -> {
            CategoryUnderProductsVo.ProductsVo productsVo = new CategoryUnderProductsVo.ProductsVo();
            productsVo.setProductsId(order.getOrderId()).setProductsName(order.getOrderName());
            return productsVo;
        }).collect(Collectors.toList());

        return productsVos;
    }

    private boolean getCouponNameJudgment(String couponName) {
        Integer countNum = this.couponBatchDao.selectCount(new QueryWrapper<CouponBatch>().lambda().eq(CouponBatch::getCouponName, couponName));
        if (countNum==0) return true;
        return false;
    }

    private List<CouponRuleVo> couponRuleVoSetNeed(List<CouponRuleVo> records) {
        List<RuleNeed> ruleNeeds = ruleNeedDao.selectList(null);
        if (CollectionUtils.isEmpty(ruleNeeds)) {
            return Collections.emptyList();
        }
        List<CouponRuleVo> couponRuleVos = records.stream().map((vo) -> {
            List<String> typeNeed = new ArrayList<>();
            ruleNeeds.forEach(need -> {
                if (vo.getRuleId().equals(need.getRuleId())) {
                    typeNeed.add(need.getCouponTypeNeed());
                }
                vo.setCouponTypeNeed(typeNeed).setCouponRangeNeed(need.getCouponRangeNeed());
            });
            return vo;
        }).collect(Collectors.toList());
        return couponRuleVos;
    }

    private Page<CouponRuleVo> getCouponRuleResPage(PageCouponBatchDTO pageCouponBatchDTO) {
        Page<CouponRuleVo> page = new Page<>(pageCouponBatchDTO.getPage(),pageCouponBatchDTO.getLimit());
        Page<CouponRuleVo> resPage=couponRuleDao.pageCouponRuleDesc(page,pageCouponBatchDTO);
        return resPage;
    }

}
